// Copyright (C) 2005 Taylor L. Riché <riche@cs.utexas.edu>
//  
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// 	$Id: Events.java 353 2005-11-07 03:31:10Z richetl $	
//

import java.io.*;
import java.util.*;

class Events
{
    class Event
    {
	public static final int PUB = 0;
	public static final int SUB = 1;
	public static final String UP = new String("up");
	public static final String DOWN = new String("down");

	private int declType;
	private String type;
	private String func;
	private String direction;

	public Event(int dt, String t, String f) {
	    if(dt == PUB) {
		assert(f == null);
	    }
	    declType = dt;
	    type = t;
	    func = f;
	}
	
	public Event(int dt, String t, String f, String d) {
	    this(dt, t, f);
	    direction = d;
	}

	public int getDeclType() {
	    return declType;
	}
	public String getType() {
	    return type;
	}
	public String getFunc() {
	    assert(declType == SUB);
	    return func;
	}
	public void printPublish(PrintStream file) {
	    if(declType == PUB) {
		String safeType = type.replaceAll("::", "_");
		file.println("\tvoid pub_" + safeType + "(lee::Event * ev = NULL) {");
		file.println("\t\tlee::Context context;");
		file.println("\t\tif(ev == NULL) {");
		file.println("\t\t\tev = new " + type + ";");
		file.println("\t\t}");
		file.println("\t\tlee::EventWrapper * evw = new lee::EventWrapper;");
		file.println("\t\tevw->ev = ev;");
		if(direction != null) {
		    if(direction.equals(UP)) {
			file.println("\t\tevw->master = dynamic_cast<lee::Subscription *>(masterCont);");
		    }
		    else {
			file.println("\t\tevw->master = dynamic_cast<lee::Subscription *>(this);");
		    }
		}
		file.println("\t\tif(context.isCU(dynamic_cast<lee::Subscription *>(this))) {");
		file.println("\t\t\tcontext.save(evw, dynamic_cast<lee::Subscription *>(this));");
		file.println("\t\t}");
		file.println("\t\telse {");
		file.println("\t\t\teventList->push_back(ev);");
		file.println("\t\t}");
		file.println("\t}");
	    }
	}

	public void printSubscribe(PrintStream file) {
	    if(declType == SUB) {
		file.println("\tvoid " + func + "(" + type + "* ev);");
	    }
	}

	public void printSubscribeStubs(PrintStream file) {
	    if(declType == SUB) {
		file.println("void\n" + func + "(" + type + "* ev)");
		file.println("{");
		file.println("}");
		file.println();
	    }
	}

	public int printSubscribeSwitch(int num, PrintStream file) {
	    if(declType == SUB) {
// 		if(first) {
// 		    file.print("\t\tif");
// 		    firstSub = false;
// 		}
// 		else {
// 		    file.print("\t\telse if");
// 		}
		file.println("\t\t" + type + "* ev" + num + ";");
		file.println("\t\tif((ev" + num + " = dynamic_cast<" + type + "*>(ev)) != NULL) {");
		file.println("\t\t\t" + func + "(ev" + num + ");");
		file.println("\t\t}");
		num++;
	    }
	    return num;
	}

	public void printSubscribeRegs(PrintStream file) {
	    if(declType == SUB) {
		file.println("\t\tregisterSub(this, new lee::SubCheckerKernel<" + type + ">);");
	    }
	}

	public void printRegister(PrintStream file) {
	    if(declType == SUB) {
		if(direction != null && direction.equals(DOWN)) {
		    file.println("\t\tif(masterSub == this)");
		}
		else if(direction != null && direction.equals(UP)) {
		    file.println("\t\tif(masterSub != this)");
		}
		file.println("\t\tmasterSub->registerSub(dynamic_cast<lee::Subscription *>(this), new lee::SubCheckerKernel<" + type + ">);");
	    }
	}
    }

    private LinkedList eventList;

    public Events() {
	eventList = new LinkedList();
    }

    public void printPublish(PrintStream file) {
	Iterator events = eventList.iterator();
	int listSize = eventList.size();
	file.println();
	for(int i = 0; i < listSize; i++) {
	    Event event = (Event)events.next();
	    event.printPublish(file);
	}
    }

    public void printSubscribeSwitch(PrintStream file) {
	file.println("\tvirtual void deliver(lee::Event * ev) {");
	file.println("\t\tassert(!masterList.empty());");
	Iterator events = eventList.iterator();
	int listSize = eventList.size();
	file.println();
	int num = 0;
	for(int i = 0; i < listSize; i++) {
	    Event event = (Event)events.next();
	    num = event.printSubscribeSwitch(num, file);
	}
	file.println("\t\tdelete ev;");
	file.println("\t}");
	file.println();
	file.println("\tvirtual void registerSubs(lee::Subscription * masterSub) {");
	events = eventList.iterator();
	for(int i = 0; i < listSize; i++) {
	    Event event = (Event)events.next();
	    event.printRegister(file);
	}
	file.println("\t}");

    }

    public void printSubscribe(PrintStream file) {
	Iterator events = eventList.iterator();
	int listSize = eventList.size();
	file.println();
	for(int i = 0; i < listSize; i++) {
	    Event event = (Event)events.next();
	    event.printSubscribe(file);
	}
    }

    public void printSubscribeStubs(PrintStream file) {
	Iterator events = eventList.iterator();
	int listSize = eventList.size();
	file.println();
	for(int i = 0; i < listSize; i++) {
	    Event event = (Event)events.next();
	    event.printSubscribeStubs(file);
	}
    }

    public void printSubscribeRegs(PrintStream file) {
	Iterator events = eventList.iterator();
	int listSize = eventList.size();
	file.println();
	for(int i = 0; i < listSize; i++) {
	    Event event = (Event)events.next();
	    event.printSubscribeRegs(file);
	}
    }

    public void addEvent(Event ev) {
	eventList.addLast(ev);
    }
}
